#include "Tabla.h"

Tabla::Tabla(string path){
		  this->archivoTabla  = new ArchivoTablasHash(path);
		  if (this->archivoTabla->getTamanio() == 0){
		    this->setTabla(new int[1]);
	        this->setTamanio(1);
	        this->tabla[0] = 0;
	        this->nueva = true;
	        this->guardar();
		  }else{
			 this->leer();
			 this->nueva = false;
		  }
}

Tabla::Tabla(int numeroCubetaInicial,string path) {

	  this->archivoTabla  = new ArchivoTablasHash(path);
	  if (this->archivoTabla->getTamanio() == 0){
	    this->setTabla(new int[1]);
        this->setTamanio(1);
        this->tabla[0] = numeroCubetaInicial;
        this->nueva = true;
        this->guardar();
	  }else{
		 this->leer();
	  }

}

/*
 * Guarda la tabla en el archivo
 */
void Tabla::guardar(){
      this->archivoTabla->actualizarTabla(this);
}

/*
 * Lee la tabla del archivo
 */
void Tabla::leer(){
   this->archivoTabla->leer(this,0);
}

int Tabla::getElementoEn(int posicion){
   return this->tabla[posicion];
}

void Tabla::setElementoEn(int posicion,int elemento){
   this->tabla[posicion] = elemento;
}

int* Tabla::getTabla(){
   return this->tabla;
}

void Tabla::setTamanio(int tamanio){
   this->tamanio = tamanio;
}

int Tabla::getTamanio(){
   return this->tamanio;
}

void Tabla::setTabla(int* tabla){
   this->tabla = tabla;
}

/*
 *
 */
void Tabla::duplicar() {
   int* nuevaTabla = new int[(this->getTamanio() * 2)];
   int k = 0;
   for (int i = 0; i < 2; i++) {
      for (int j = 0; j < (this->getTamanio()); j++) {

         nuevaTabla[j + k] = this->getTabla()[j];
      }
      k = this->getTamanio();
   }
   this->setTamanio(this->getTamanio() * 2);
   delete [] this->tabla;
   this->tabla = nuevaTabla;
   this->guardar();

}

/*
 *
 */
void Tabla::truncar() {
   int tamanioMitad = (this->getTamanio() / 2);
   int* mitadDeArriba = this->tabla + tamanioMitad;
   int* mitadDeAbajo = this->tabla;
   bool iguales = true;
   for (int i = 0; i < tamanioMitad; i++) {
      if (mitadDeAbajo[i] != mitadDeArriba[i]) {
         iguales = false;
      }
   }
   if (iguales && tamanioMitad != 0) {
      int* nuevaTabla = new int[tamanioMitad];
      for (int i = 0; i < tamanioMitad; i++) {
         nuevaTabla[i] = this->tabla[i];
      }
      delete [] this->tabla;
      this->tabla = nuevaTabla;
      this->setTamanio(tamanioMitad);
   }
      this->guardar();
}

/*
 *
 */
void Tabla::actualizar(int posicion, int td, int numeroCubeta) {
   int mov = td;

   this->setElementoEn(posicion,numeroCubeta);
   int arriba = posicion + mov;

   if (arriba >= this->getTamanio()) {
      arriba = arriba - this->getTamanio();
   }
   while (arriba != posicion) {
      this->setElementoEn(arriba,numeroCubeta);
      arriba = arriba + mov;
      if (arriba >= this->getTamanio())
         arriba = arriba - this->getTamanio();

   }
    this->guardar();
}

/*
 * Si el archivo no existia : true
 *       Si el archivo existia: false
 */
bool Tabla::esNueva() const
{
    return nueva;
}

unsigned int Tabla::getTamanioDelBuffer(){
    // Cantidad de Elementos
    int tamanioDelBuffer =  sizeof(int);
	//tamanio de los elementos* cantidad
	tamanioDelBuffer += (this->getTamanio() * sizeof(int));

    return tamanioDelBuffer;
}

void Tabla::hidratarse(char* buffer, unsigned int tamanioDelBuffer){

         //escribo el buffer en el stringStream
        stringstream* ss = new stringstream(stringstream::in | stringstream::out | stringstream::binary);
        ss->seekg(0, ios::beg);
        ss->write(buffer, tamanioDelBuffer);

        //int Cantidad Registros
        unsigned int cantidadElementos;
        ss->read((char*) &(cantidadElementos), sizeof(int));
        this->setTamanio(cantidadElementos);

    	this->setTabla(new int[cantidadElementos]);
        //Elemento por Elemento
        unsigned int elemento;
        for (unsigned int i = 0; i < cantidadElementos; i++) {
                   ss->read((char*) &(elemento), sizeof(int));
                   this->getTabla()[i]= elemento;
        }

        delete ss;
}

char* Tabla::construirBuffer(){

        //agrupo los atributos
        stringstream* ss = new stringstream(stringstream::in | stringstream::out | stringstream::binary);
        ss->seekp(0, ios::end);

        //Cantidad de Elementos
        unsigned int cantidadDeElementos = this->getTamanio();
        ss->write((char*) &cantidadDeElementos, sizeof(int));

        //Elemento por Elemento de la tabla
		unsigned int elemento;
        for (unsigned int i = 0; i < cantidadDeElementos; i++) {
			elemento = this->getTabla()[i];
			ss->write((char*) &elemento, sizeof(int));
        }

       //construyo el buffer
        unsigned int tamanioDelBuffer = this->getTamanioDelBuffer();
        char* buffer = new char[tamanioDelBuffer];
        ss->read(buffer, tamanioDelBuffer);
        delete ss;

        //lo devuelvo
        return buffer;
}

void Tabla::marcarComoBorrado(){

}

Tabla::~Tabla() {
  delete [] this->tabla;
  delete this->archivoTabla;
}

